;
; Copyright (c) Microsoft Corporation.  All rights reserved.
;
;
; Use of this sample source code is subject to the terms of the Microsoft
; license agreement under which you licensed this sample source code. If
; you did not accept the terms of the license agreement, you are not
; authorized to use this sample source code. For the terms of the license,
; please see the license agreement between you and Microsoft or, if applicable,
; see the LICENSE.RTF on your install media or the root of your tools installation.
; THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
;
;
; (C) Copyright 2006 Marvell International Ltd.
; All Rights Reserved
;
;
; INTEL CONFIDENTIAL
; Copyright 2005 - 2006 Intel Corporation. All Rights Reserved.
;
; The source code contained or described herein and all documents
; related to the source code (Material) are owned by Intel Corporation
; or its suppliers or licensors.  Title to the Material remains with
; Intel Corporation or its suppliers and licensors. The Material contains
; trade secrets and proprietary and confidential information of Intel
; or its suppliers and licensors. The Material is protected by worldwide
; copyright and trade secret laws and treaty provisions. No part of the
; Material may be used, copied, reproduced, modified, published, uploaded,
; posted, transmitted, distributed, or disclosed in any way without Intel's
; prior express written permission.
;
; No license under any patent, copyright, trade secret or other intellectual
; property right is granted to or conferred upon you by disclosure or
; delivery of the Materials, either expressly, by implication, inducement,
; estoppel or otherwise. Any license under such intellectual property rights
; must be express and approved by Intel in writing.
;
;
;*********************************************************************************
;
;  FILENAME:    xlli_LowLev_Init_opt.s
;
;  PURPOSE:     This XLLI file contains optional Low Level Initialization code
;               for the Monahans L processor.
;
;  LAST MODIFIED:  6-Jan-2006
;
;******************************************************************************
;
        INCLUDE  xlli_Monahans_defs.inc         ; Monahans specific include file
        INCLUDE  xlli_Littleton_defs.inc         ; Zylonite specific include file
;
        AREA    |text|, CODE, READONLY, ALIGN=5         ; Align =5 required for "ALIGN 32" feature to work.
;
; List of Low Level Init functions in this source code include:
;
        EXPORT xlli_DDR_HCAL            ; Hardware delay line calibration routine
        EXPORT xlli_DDR_SCAL            ; Software delay line calibration routine
        EXPORT xlli_intr_init           ; Interrupt initialization (masks all interrupts)
        EXPORT xlli_freq_change         ; Frequency change sequence
        EXPORT xlli_l2cache_enable      ; Level 2 cache enable
        EXPORT xlli_icache_enable       ; Enable I-Cache, D-Cache, and Branch Target Buffer
        EXPORT xlli_setPTB              ; Set the Page Tabe Base address (used for sleep resets)
        EXPORT xlli_initPageTable       ; Initialize Page Table for MMU unit
        EXPORT xlli_initPageTable_var   ; Initialize Page Table for MMU unit (base addr in r1)
        EXPORT xlli_MMU_init            ; Initialize the Memory Management Unit
        EXPORT xlli_goVirtual           ; Make the transition from physical address to virtual address
        EXPORT xlli_set_clocks          ; Set system clocks according to platform switch settings

        LTORG
;
; *****************************************************
; **********                                 **********
; ********** HARDWARE DELAY LINE CALIBRATION **********
; **********                                 **********
; *****************************************************
;
; This xlli subroutine performs a hardware calibration for the dynamic
; memory strobe delay lines DQS[3:0].
;
;       NOTES:
;
;       In 16-bit bus mode, all functions corresponding to strobes DQS[3:2] are disabled.
;       DDR_SCAL (SW calibration enable) should be clear if using SDR_DRAM.
;
;       INPUT PARAMETERS:
;
;               r0 = Address of dynamic memory control registers base (Physical 0x4810_0000).
;
;       RETURNED STATUS/VALUE(s):
;
;               NONE
;

xlli_DDR_HCAL   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        stmfd   sp!,    {r1, lr}                ; Save used registers
                ENDIF

	ldr     r1,     =(xlli_DDR_HCAL_HCEN:OR:xlli_DDR_HCAL_HCPROG:OR:xlli_DDR_HCAL_HCPW:OR:xlli_DDR_HCAL_HCOD)
        str     r1,     [r0, #xlli_DDR_HCAL_offset]     ; Load data into DDR_HCAL register 
;
;       Wait for hardware calibration to complete
;
xlli_h1 ldr     r1,     [r0, #xlli_DMCISR_offset]       ; Get results of the evaluation
        ands    r1,     r1,     #xlli_DMCISR_DLP        ; Extract DLP bit
;        beq     xlli_h1                                 ; Loop until set
        str     r1,     [r0, #xlli_DMCISR_offset]       ; Clear sticky DLP bit

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        ldmfd   sp!,    {r1, pc}                ; Return to caller via the stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF
        ENDFUNC

;********************************************************************************************
;
; *****************************************************
; **********                                 **********
; ********** SOFTWARE DELAY LINE CALIBRATION **********
; **********                                 **********
; *****************************************************
;
; This xlli subroutine performs a software calibration for the dynamic
; memory strobe delay lines DQS[3:0].
;
;       NOTES:
;
;       In 16-bit bus mode, all functions corresponding to strobes DQS[3:2] are disabled.
;       DDR_SCAL (SW calibration enable) should be clear if using SDR_DRAM. Memory should
;       be operating at maximum frequency to use the software calibration method.
;
;       INPUT PARAMETERS:
;
;               r0 = Address of dynamic memory control registers base (Physical 0x4810_0000).
;               r1 = Address of 8-byte DDR-SDRAM area to use for strobe delay test.
;
;       RETURNED STATUS/VALUE(s):
;
;               NONE
;

xlli_DDR_SCAL   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
         stmfd   sp!,    {r2-r9, lr}            ; Save used registers
                ENDIF
;
;       Store a test pattern to memory
;
        ldr     r2,     =0x124837EC     ; Test pattern
        mvn     r3,     r2              ; Invert test pattern in r3
        str     r2,     [r1]            ; Store test pattern
        str     r3,     [r1, #4]        ; Store inverted pattern
;
;       Set up DDR_SCAL register to do software calibration. Inital conditions
;       are set up by writing 0x80000000 to the DDR_SCAL register
;
        ldr     r4,     =0x00808000                     ; Inital value
        str     r4,     [r0, #xlli_DDR_SCAL_offset]     ; Set up SCAL register
        ldr     r4,     [r0, #xlli_DDR_SCAL_offset]     ; Read back to latch
        ldr     r4,     =0x80808000                     ; Enable software cal, & auto increment by 2
        str     r4,     [r0, #xlli_DDR_SCAL_offset]     ; Set up SCAL register    
        mov     r6,     #0                              ; Clear a work register
        mov     r7,     #0                              ; Clear a work register
        mov     r8,     #0                              ; Clear a work register
        mov     r9,     #0                              ; Clear a work register
;
;       Read the test pattern back from SDRAM saving data for later evaluation.
;       There are four strobe delays line to be calibrated, one strobe for
;       byte of data.
;
;       When the data is being read back, it may change from bad to good and
;       back to bad several times before the real data eye becomes apparent.
;       This code looks for the largest number of good reads for each byte
;       and sets the delay window for the center of this data eye. Four registers
;       are used to keep track of the largest window. R6 ends up containing the
;       delay setting of the last BAD read for the largest window in the 
;       approprite byte for the stobe. R7 contains the number of sucessful reads
;       (again by byte) before the data went bad again. R8 and r9 perform essentally
;       the same function but are the "working rregisters" during the readback
;       process. Whenever the successful count value in a byte of r9 becomes larger
;       than the sucessful count value in r7, the data for that byte is copied from
;       r8 into r6 and from r9 into r7. Thus, at the end of the calibration, each
;       byte in r6 will have the starting dealy count for the coresponding strobe,
;       and r7 will contain the width of the dealy in successful reads. The delay
;       to the center of the data eye is the value in each r6 bye added to the
;       count in r7 if the dealys are incremented by two, or is r7 divided by
;       two if the delay increment is 1 on sucessive reads.
;
;       r2 contins expected test pattern.
;       r3 contains the data that is read back (below)
;       r4, r5 are temp use registers
;       r6 saves (in position) the dealy start value of the largest data eye
;       r7 saves (in position) the number of successful reads for the largest data eye
;       r8 saves the delay time from the latest INVALID read (by byte)
;       r9 saves the count of the number of successful reads
;       
xlli_sr ldr     r3,     [r1]                            ; Read test pattern data
;
;       ************************
;       ***** BYTE 0 TESTS *****
;       ************************
;
        and     r4,     r2,     #0xFF   ; r4 = expected test pattern for byte 0
        and     r5,     r3,     #0xFF   ; r5 = returned test pattern for byte 0
        cmp     r4,     r5              ; Does the byte data match?
        beq     xlli_s0s                ; Yes - skip over the following
;
;       Update r8 with this delay time and zero out coresponding byte in r9
;
        ldr     r4,     [r0, #xlli_DDR_SCAL_offset]     ; Read SCAL register
        and     r4,     r4,     #0x7F                   ; Get the delay value
        bic     r8,     r8,     #0x7F                   ; Clear the previous data
        orr     r8,     r8,     r4                      ; Save this delay value
        bic     r9,     r9,     #0xFF                   ; Zero out the count in r9
        b       xlli_s1                                 ; Test next byte
;
;       Increment count in r9 and copy r8/r9 data to r6/r7 if count in r9
;       exceeds the count in r7.
;
xlli_s0s
        add     r9,     r9,     #1      ; Increment count in r9
        and     r4,     r7,     #0xFF   ; Get byte 0 count in r7 (largest data eye size)
        and     r5,     r9,     #0xFF   ; Get byte 0 count in r9 (working register)
        cmp     r4,     r5              ; Is this data eye larger than the saved one?
        bpl     xlli_s1                 ; No - test next byte
;
;       A larger data eye has been found - copy r8/r9 data into r6/r7
;
        bic     r6,     r6,     #0xFF   ; Clear data in r6
        bic     r7,     r7,     #0xFF   ; Clear data in r7
        and     r4,     r8,     #0xFF   ; Extract r8 data into r4
        and     r5,     r9,     #0xFF   ; Extract r9 data into r5
        orr     r6,     r6,     r8      ; Copy r8 data into r6
        orr     r7,     r7,     r9      ; Copy r9 data into r7
;
;       ************************
;       ***** BYTE 1 TESTS *****
;       ************************
;
xlli_s1 and     r4,     r2,     #0xFF00 ; r4 = expected test pattern for byte 0
        and     r5,     r3,     #0xFF00 ; r5 = returned test pattern for byte 0
        cmp     r4,     r5              ; Does the byte data match?
        beq     xlli_s1s                ; Yes - skip over the following
;
;       Update r8 with this delay time and zero out coresponding byte in r9
;
        ldr     r4,     [r0, #xlli_DDR_DLS_offset]      ; Read SCAL register
        and     r4,     r4,     #0x7F00                 ; Get the delay value
        bic     r8,     r8,     #0x7F00                 ; Clear the previous data
        orr     r8,     r8,     r4                      ; Save this delay value
        bic     r9,     r9,     #0xFF00                 ; Zero out the count in r9
        b       xlli_s2                                 ; Test next byte
;
;       Increment count in r9 and copy r8/r9 data to r6/r7 if count in r9
;       exceeds the count in r7.
;
xlli_s1s
        add     r9,     r9,     #0x100  ; Increment count in r9
        and     r4,     r7,     #0xFF00 ; Get byte 0 count in r7 (largest data eye size)
        and     r5,     r9,     #0xFF00 ; Get byte 0 count in r9 (working register)
        cmp     r4,     r5              ; Is this data eye larger than the saved one?
        bpl     xlli_s2                 ; No - test next byte
;
;       A larger data eye has been found - copy r8/r9 data into r6/r7
;
        bic     r6,     r6,     #0xFF00 ; Clear data in r6
        bic     r7,     r7,     #0xFF00 ; Clear data in r7
        and     r4,     r8,     #0xFF00 ; Extract r8 data into r4
        and     r5,     r9,     #0xFF00 ; Extract r9 data into r5
        orr     r6,     r6,     r8      ; Copy r8 data into r6
        orr     r7,     r7,     r9      ; Copy r9 data into r7
;
;       ************************
;       ***** BYTE 2 TESTS *****
;       ************************
;
xlli_s2 and     r4,     r2,     #0xFF0000       ; r4 = expected test pattern for byte 0
        and     r5,     r3,     #0xFF0000       ; r5 = returned test pattern for byte 0
        cmp     r4,     r5                      ; Does the byte data match?
        beq     xlli_s2s                        ; Yes - skip over the following
;
;       Update r8 with this delay time and zero out coresponding byte in r9
;
        ldr     r4,     [r0, #xlli_DDR_DLS_offset]      ; Read SCAL register
        and     r4,     r4,     #0x7F0000               ; Get the delay value
        bic     r8,     r8,     #0x7F0000               ; Clear the previous data
        orr     r8,     r8,     r4                      ; Save this delay value
        bic     r9,     r9,     #0xFF0000               ; Zero out the count in r9
        b       xlli_s3                                 ; Test next byte
;
;       Increment count in r9 and copy r8/r9 data to r6/r7 if count in r9
;       exceeds the count in r7.
;
xlli_s2s
        add     r9,     r9,     #0x10000         ; Increment count in r9
        and     r4,     r7,     #0xFF0000       ; Get byte 0 count in r7 (largest data eye size)
        and     r5,     r9,     #0xFF0000       ; Get byte 0 count in r9 (working register)
        cmp     r4,     r5                      ; Is this data eye larger than the saved one?
        bpl     xlli_s3                         ; No - test next byte
;
;       A larger data eye has been found - copy r8/r9 data into r6/r7
;
        bic     r6,     r6,     #0xFF0000       ; Clear data in r6
        bic     r7,     r7,     #0xFF0000       ; Clear data in r7
        and     r4,     r8,     #0xFF0000       ; Extract r8 data into r4
        and     r5,     r9,     #0xFF0000       ; Extract r9 data into r5
        orr     r6,     r6,     r8              ; Copy r8 data into r6
        orr     r7,     r7,     r9              ; Copy r9 data into r7
;
;       ************************
;       ***** BYTE 3 TESTS *****
;       ************************
;
xlli_s3 and     r4,     r2,     #0xFF000000     ; r4 = expected test pattern for byte 0
        and     r5,     r3,     #0xFF000000     ; r5 = returned test pattern for byte 0
        cmp     r4,     r5                      ; Does the byte data match?
        beq     xlli_s3s                        ; Yes - skip over the following
;
;       Update r8 with this delay time and zero out coresponding byte in r9
;
        ldr     r4,     [r0, #xlli_DDR_DLS_offset]      ; Read SCAL register
        and     r4,     r4,     #0x7F000000             ; Get the delay value
        bic     r8,     r8,     #0x7F000000             ; Clear the previous data
        orr     r8,     r8,     r4                      ; Save this delay value
        bic     r9,     r9,     #0xFF000000             ; Zero out the count in r9
        b       xlli_s4                                 ; Test next byte
;
;       Increment count in r9 and copy r8/r9 data to r6/r7 if count in r9
;       exceeds the count in r7.
;
xlli_s3s
        add     r9,     r9,     #0x1000000       ; Increment count in r9
        and     r4,     r7,     #0xFF000000     ; Get byte 0 count in r7 (largest data eye size)
        and     r5,     r9,     #0xFF000000     ; Get byte 0 count in r9 (working register)
        cmp     r4,     r5                      ; Is this data eye larger than the saved one?
        bpl     xlli_s4                         ; No - test next byte

;       A larger data eye has been found - copy r8/r9 data into r6/r7
;
        bic     r6,     r6,     #0xFF000000     ; Clear data in r6
        bic     r7,     r7,     #0xFF000000     ; Clear data in r7
        and     r4,     r8,     #0xFF000000     ; Extract r8 data into r4
        and     r5,     r9,     #0xFF000000     ; Extract r9 data into r5
        orr     r6,     r6,     r8              ; Copy r8 data into r6
        orr     r7,     r7,     r9              ; Copy r9 data into r7
;
;       Write the inverted test pattern to SDRAM to "pre-charge" the data line
;       to the opposite polarity of the expected data.
; 
xlli_s4 mvn     r3,     r2                      ; Invert test pattern in r3
        str     r3,     [r1, #4]                ; Store inverted pattern to precharge data lines
;
;       Check to see if the delay time has been maxed out
;
        ldr     r4,     [r0, #xlli_DDR_DLS_offset]     ; Read SCAL register
        and     r4,     r4,     #0x7E           ; Get the present delay setting
        cmp     r4,     #0x7E                   ; Is the delay time maxed out?
        bne     xlli_sr                         ; Nope, Do another data read
;
;       The data eye has been painted and all delay data has been collected.
;       Locate the center of the data eye and program these values in for the
;       strobe delay times.
;
;       Recall that:
;       r6 saves (in position) the start dealy value for the largest data eye found.
;       r7 saves (in position) the number of successful reads in this data eye.
;
;       Because the XLLI code set up the SCAL register to increment dealy units
;       by a factor of two and r7 contains the number of successful reads, the
;       center of the data eye is found simply by adding r7 to r6.
;
        add     r5,     r6,     r7      ; Generate data for SCAL register
;
;       Update the DDR_SCAL register
;
        orr     r5,     r5,     #0x80000000             ; Set this bit to update register
        str     r5,     [r0, #xlli_DDR_SCAL_offset]     ; Set up SCAL register

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        ldmfd   sp!,    {r2-r9, pc}             ; Return to caller via the stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF
        ENDFUNC
;
;*******************************************************************************
;
; ***********************************
; **********               **********
; ********** xlli_DFC_Init **********   INITALIZE DATA FLASH CONTROLLER
; **********               **********
; ***********************************
;
; The sequence below is based on the recommended memory initializing procedure
; recommended in the (Monahans) Static Memory Controller
;
;       INPUT PARAMETER REQUIRED:
;
;               R0 = Data Flash Memory Control Reg Base Address
;
;       RETURNED STATUS/VALUE(s):
;
;               NONE
;

xlli_DFC_init  FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        stmfd   sp!,    {r1-r3, lr}             ; Save r1-r3, & link on stack
                ENDIF

;       (more setup to be included later)

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        ldmfd   sp!,    {r1-r3, pc}             ; return to caller via stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF

        LTORG

;**************************************************************************************************
;
; ******************************************************
; **********                                  **********
; ********** INITIALIZE (MASK) ALL INTERRUPTS **********
; **********                                  **********
; ******************************************************
;
; NOTE: On system reset, all interrupts should be cleared by hardware.
;       This enforces disabling of all interrupts to HW boot default conditions.
;
xlli_intr_init   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        stmfd   sp!,    {r0, lr}                ; Save r0, & link on stack
                ENDIF

        ldr     r0,  =0x0               ; zero out a work register
        mcr     p6, 0, r0, c1, C0, 0    ; Clear ICMR register
        mcr     p6, 0, r0, c7, C0, 0    ; Clear ICMR2 register
        mcr     p6, 0, r0, c2, C0, 0    ; Clear ICLR register
        mcr     p6, 0, r0, c8, C0, 0    ; Clear ICLR2 register

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        ldmfd   sp!,    {r0, pc}                ; Return to caller via stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF

        ENDFUNC

;**************************************************************************************************
;
; ***********************************************
; **********                           **********
; ********** FREQUENCY CHANGE SEQUENCE **********
; **********                           **********
; ***********************************************
;
; This subroutine initiates the frequency change sequence and restarts the memory controller
;

xlli_freq_change   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0, r1, lr}            ; save r0, r1, & link on stack
                ENDIF

        mrc     p14, 0, r0, c6, c0, 0       ; Get present status (preserve Turbo and Fast Bus bits)
        orr     r0,  r0,  #2                ; Set the F bit
        mcr     p14, 0, r0, c6, c0, 0       ; initiate the frequency change sequence - Wheeeeeeeee!
;
;       If the clock frequency is chaged, the MDREFR Register must be  rewritten, even
;       if it's the same value. This will result in a refresh being performed and the
;       refresh counter being reset to the reset interval.
;
        ldr     r0,  =xlli_DMEMREGS_PHYSICAL_BASE   ; Get memory controller base address
        ldr     r1,  [r0, #xlli_MDREFR_offset]      ; Get the current state of MDREFR
        str     r1,  [r0, #xlli_MDREFR_offset]      ; Re-write this value

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined
        ldmfd   sp!,    {r0, r1, pc}            ; Return to caller via the stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF

        ENDFUNC
;
;**************************************************************************************************
;
; *************************************
; **********                 **********
; ********** ENABLE L2 CACHE **********
; **********                 **********
; *************************************
;
; This code segment enables the level 2 cache buffer.
;
xlli_l2cache_enable   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0, lr}                ; save r0, & link on stack
                ENDIF

        mrc    p15, 0, r0, c1, c0, 0            ; Get the contents of the ARM control register
        mov    r0,  r0, LSL #18                 ; Upper 18-bits must be written as zero...
        mov    r0,  r0, LSR #18                 ; ....clear them now

        orr    r0,  r0, #xlli_control_l2cache    ; set the l2-cache bit

        ; This code segment writes the contents of r0 into the ARM control register.
        ; Note: you must either format the contents of w1 so that reserved bits
        ;       are written with the proper value, or get the getARMControl values and
        ;       modify the control bits you need.
                ;
        ; make sure this is first instruction in a cache line

        b      xlli_7           ; Branch to code below (legacy XLLI code)
;
;**************************************************************************************************
;
; **********************************************************************
; **********                                                  **********
; ********** ENABLE I-CACHE, D-CACHE AND BRANCH TARGET BUFFER **********
; **********                                                  **********
; **********************************************************************
;
; This code segment enables the Instruction Cache, Data Cache, and the Branch Target Buffer.
;
xlli_icache_enable   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0, lr}                ; save r0, & link on stack
                ENDIF

        mrc    p15, 0, r0, c1, c0, 0            ; Get the contents of the ARM control register
        mov    r0,  r0, LSL #18                 ; Upper 18-bits must be written as zero...
        mov    r0,  r0, LSR #18                 ; ....clear them now

        orr    r0,  r0, #xlli_control_icache    ; set the i-cache bit
        orr    r0,  r0, #xlli_control_btb       ; set the btb bit
        orr    r0,  r0, #xlli_control_dcache    ; set the d-cache bit

        ; This code segment writes the contents of r0 into the ARM control register.
        ; Note: you must either format the contents of w1 so that reserved bits
        ;       are written with the proper value, or get the getARMControl values and
        ;       modify the control bits you need.
                ;
        ; make sure this is first instruction in a cache line

        b      xlli_7
        ALIGN  32
xlli_7
        mcr    p15, 0, r0, c1, c0, 0

        ; This code segment guarantees that previous writes to coprocessor 15 have
        ; completed. Depending on what is being modified in cp15 (turning on
        ; the mmu, for example), these instructions may need to be executed
        ; from the icache.

        mrc    p15, 0, r0, c1, c0, 0
        mov    r0,  r0
        sub    pc,  pc, #4

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r0, pc}                ; return to the caller via the stack
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF

        ENDFUNC

;**************************************************************************************************
;
; *****************************************
; **********                     **********
; ********** SET PAGE TABLE BASE **********
; **********                     **********
; *****************************************
;
; Set page table base (used after a sleep reset)
;
xlli_setPTB    FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0, lr}                ; Save r0 & link on stack
                ENDIF

        ldr    r0,  =xlli_p_PageTable ; Get address of Page Table base
        mcr    p15, 0, r0, c2, c0, 0  ; Load Page Table base into CP 15

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r0, pc}                ; Return to caller via stack
                ELSE
        mov    pc,  lr                  ; Non stack return
                ENDIF

                ENDFUNC

;**************************************************************************************************
;
; ***************************************************************
; **********                                           **********
; ********** INITIALIZE PAGE TABLES FOR MEMORY MAPPING **********
; **********                                           **********
; ***************************************************************
;
; Init the Page Table area of memory by writting zeros out to the table
; The alternate entry may be used with r1 = the page table base address
;

xlli_initPageTable   FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0-r2, lr}             ; Save r0-r2 & link on stack
                ENDIF

        ldr    r1,  =xlli_p_PageTable ; Get address of Page Table base

xlli_initPageTable_var
        mcr    p15, 0, r1, c2, c0, 0 ; Load Page Table base into CP 15
;
;       zero-out the page table memory region
;
        mov    r2,  #xlli_s_PageTable ; get table size
        mov    r0,  #0
xlli_8
        subs   r2,  r2,  #4          ; Increment offset into table
        str    r0,  [r1, r2]         ; Clear table entry
        bne    xlli_8                ; Keep looping until done

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r0-r2, pc}             ; Return to caller via stack
                ELSE
        mov    pc,  lr                  ; Non stack return
                ENDIF

        ENDFUNC

;**************************************************************************************************
;
; ***********************************************************
; **********                                       **********
; ********** INITIALIZE THE MEMORY MANAGEMENT UNIT **********
; **********                                       **********
; ***********************************************************
;
;       Initialize the memory management unit
;

xlli_MMU_init      FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0-r1, lr}             ; Save r0-r1 & link on stack
                ENDIF

        ; set DACR
        ldr    r1,  =xlli_DACR
        mcr    p15, 0, r1, c3, c0, 0       ; Set DACR

        ldr    r0,  =xlli_PID
        mov    r0,  r0, LSR #25            ; Clear the lo-order 25 bits
        mov    r0,  r0, LSL #25            ; (may be unnecessary)
        mcr    p15, 0, r0, c13, c0, 0      ; Set PID

        mrc    p15, 0, r1, c1, c0, 1       ; Get the current aux control settings

;       extract the control bits such that reserved bits are 0, this will
;       prep the bits for a subsequent write.

        and    r1,  r1,  #0x33
        orr    r1,  r1,  #xlli_CONTROL_MINIDATA_01 ; orr in the mini-data cache attributes

        mcr    p15, 0, r1, c1, c0, 1       ; Write back the new settings

;       invalidate and enable the BTB

        mcr    p15, 0, r1, c7, c5, 6       ; invalidate the Branch Target Buffer
;
;       enable the BTB
;
        mrc    p15, 0, r1, c1, c0, 0
        mov    r1,  r1, LSL #18            ; Upper 18 bits must be
        mov    r1,  r1, LSR #18            ; written as zeros
        orr    r1,  r1, #xlli_CONTROL_BTB  ; set the BTB bit

        b     xlli_9                       ; 1st instruction on cache line
        ALIGN 32
xlli_9
        mcr    p15, 0, r1, c1, c0, 0       ; write the data back
        mrc    p15, 0, r1, c2, c0, 0       ; Insure that the write completes
        mov    r1,  r1                     ; before continuing
        sub    pc,  pc,  #4

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r0-r1, pc}             ; Return to caller via stack
                ELSE
        mov    pc,  lr                  ; Non stack return
                ENDIF

        ENDFUNC

;**************************************************************************************************
;
; **************************************************************
; **********                                          **********
; ********** FIRE UP THE MMU - SWITCH TO VIRTUAL MODE **********
; **********                                          **********
; **************************************************************
;
;      Make the transistion from physical mode to virtual mode.
;
;      This subroutine assumes thaqt execution is from boot ROM and that
;      the MMU is disabled when this subroutine is called.
;
;      NOTES:
;
;      1. The memory system must already be up and running.
;      2. The page table must be initalized (zeroed out)
;      3. The memory to be accessed must have their page table entries filled in.
;      4. The MMU needs to be initialized first.
;      5. When this subroutine returns to the caller, all addresses are virtual.
;
;      Typically this would be the last low level init subroutine to be run before
;      control is turned over to an operating system.
;

xlli_goVirtual  FUNCTION
;
;       (1) Temporarily overwrite page table entry that maps where we are now.
;
;       This code section effectivly makes the table entry where the program counter
;       (pc) would point now and, the table entry where the new pc value will point,
;       (after going to virtual addressing) result in the code pointing to the same
;       physical address regardless of which pc value is used. This is to
;       cover those cases where the pc is altered after the jump to virtual
;       addresing. If the sections are idenity (flat) mapped, then the following
;       code basicly rewrites a single table entery with a copy of itself. Once the
;       pc has been altered to the virtual address, the original table entry for the
;       address space we are now is is restored to its original value.
;
;       CAUTION: If the page table is mapped to virtual address different from the physical
;       address, this code is likely to result in an exception to 0x10 (Data Abort) unless
;       you modify the code in the section to take this into account.
;
                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r0-r3, lr}             ; Save r0-r3 & link on stack
                ENDIF;

        ldr   r1,  =xlli_p_PageTable       ; Get address of Page Table base

        mov   r0,  pc,  LSR #(20)          ; Current execution location (divide by 1 Mb)
        mov   r0,  r0,  LSL #(2)           ; Insure lower two bits are zero
        add   r0,  r0,  r1                 ; Point to RAM page table entry for this address space
        ldr   r3,  [r0]                    ; Save the existing table entry in r3
;
;       Do not alter r3 or r0 as we will need them later...
;
        ldr   r2,  =(xlli_v_xbBOOTROM :SHR: (18))
        add   r2,  r2,  r1                 ; Point to new (virtual) ROM page table entry
        ldr   r1,  [r2]                    ; Get this (virtural address) table entry....
;
;       Overwrite RAM entry for current (physical address) table entry
;
        str   r1,  [r0]                    ; ....and place it in the current table entry.

;       end-of-part (1)
; -------------------------------------------------
;       (2) setup to enable the MMU
;
;       Generate (in r1) the virtual address the code will jump to once the
;       transition has been made to virtual address mode.
;
        add   r1,  pc, #xlli_12 - (.+8)    ; Load address of xlli_12 into r1
        add   r1,  r1,  #xlli_v_xbBOOTROM  ; add offset to virtual ROM address
;
;       Invalidate both TLBs
;
        mcr p15, 0, r2, c8, c7, 0          ; Invalidates both instruction and data TLBs
;
;       enable mmu
;
        mrc   p15, 0, r2, c1, c0, 0        ; Read current settings in control reg
        mov   r2,  r2, LSL #18             ; Upper 18-bits must be written as zero,
        mov   r2,  r2, LSR #18             ; ... clear them now.
;
;               Set ROM protection, Clear System protection, Set MMU bit
;
        orr   r2, r2, #xlli_control_r      ; set the ROM Protection bit
        bic   r2, r2, #xlli_control_s      ; clear the System Protection bit
        orr   r2, r2, #xlli_control_mmu    ; set the MMU bit
;
;       Write back the new value
;
        b      xlli_11                     ; make sure this is first instruction in a cache line
        ALIGN  32
xlli_11
        mcr    p15, 0, r2, c1, c0, 0       ; Go Virtual!
        mrc    p15, 0, r2, c2, c0, 0       ; Insure that the write completes
        mov    r2,  r2                     ; before continuing
        sub    pc,  pc,  #4
;
;       invalidate both caches, btb
;
        mcr    p15, 0, r2, c7, c7, 0

        mov    pc,  r1                     ; Load virtual address into the pc
        nop                                ; nop instructions to "empty the pipeline"
        nop
        nop
        nop
        nop
        nop
xlli_12
        add   lr,  lr,  #xlli_v_xbBOOTROM  ; Update the link register return address

;       end-of-part (2)
; -------------------------------------------------
;       (3) restore the overwritten page table entry, flush all caches
;       The following instruction assumes the page table is idenity mapped!
;
        str   r3,  [r0]                    ; This restores original page table entry
;
;       Invalidate both TLBs and caches
;
        mcr   p15, 0, r2, c8, c7, 0        ; Invalidates both instruction and data TLBs
        mcr   p15, 0, r2, c7, c7, 0        ; invalidate both caches, BTB

        nop                                ; Make sure the pipe is empty
        nop
        nop
        nop
        nop
        nop
;
;       end-of-part (3)
;       -------------------------------------------------
;       set up cache memory for use
;
        mcr   p15, 0, r1, c7, c6, 0        ; Invalidates the D cache
        mcr   p15, 0, r1, c8, c6, 0        ; Invalidates the data TLB

        mrc    p15, 0, r2, c2, c0, 0       ; Insure that the write completes
        mov    r2,  r2                     ; before continuing
        sub    pc,  pc,  #4
;
;       invalidate the BTB
;
        mcr    p15, 0, r1, c7, c5, 6       ; invalidate the Branch Target Buffer
;
;       Enable ICache, DCache, BTB
;
        mrc   p15, 0, r2, c1, c0, 0        ; Read current settings in control reg
        mov   r2,  r2, LSL #18             ; Upper 18-bits must be written as zero,
        mov   r2,  r2, LSR #18             ; ... clear them now.

        orr   r2, r2, #xlli_control_dcache ; set the DCache bit
        orr   r2, r2, #xlli_control_icache ; set the ICache bit
        orr   r2, r2, #xlli_control_btb
;
;       Write back the new value
;
        b      xlli_13                     ; make sure this is first instruction in a cache line
        ALIGN  32
xlli_13
        mcr    p15, 0, r2, c1, c0, 0
        mrc    p15, 0, r2, c2, c0, 0       ; Insure that the write completes
        mov    r2,  r2                     ; before continuing
        sub    pc,  pc,  #4

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r0-r3, pc}             ; Return to caller via stack
                ELSE
        mov    pc,  lr                  ; Non stack return
                ENDIF
        ENDFUNC
;
;*******************************************************************************
;
; *************************************
; **********                 **********
; ********** xlli_set_clocks **********  SET SYSTEM CLOCKS ACCORDING TO
; **********                 **********  PLATFORM SWITCH SETTINGS
; *************************************  (for Monahans P only)
;
;       Sets the clocks on Monahans to preset frequencies based on the
;       Zylonite platform switch settings
;
;       INPUT PARAMETERS:
;
;               NONE
;
;       RETURNED STATUS/VALUE(s):
;
;       r0 will contain the switch settings read on the platform
;
;       r0    SW2     SW12  CORE_FRQ   HS I/O  DDR_FRQ   iSRAM     EMPI   DF_SCLK
;       ==  ======  ======  ========  =======  =======  =======  =======  =======
;        3     DOT     DOT   104 MHz  104 MHz  260 MHz  104 MHz   26 MHz   13 MHz
;        2     DOT  NO_DOT   208 MHz  156 MHz  260 MHz  208 MHz   26 MHz   13 MHz
;        1  NO_DOT     DOT   416 MHz  208 MHz  260 MHz  312 MHz   52 MHz   26 MHz
;        0  NO_DOT  NO_DOT   624 MHz  208 MHz  260 MHz  312 MHz   52 MHz   26 MHz
;
xlli_set_clocks  FUNCTION

                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        stmfd   sp!,    {r1-r5, lr}             ; Save r1-r5, & link on stack
                ENDIF
;
;       GPIO_4 alternate function must be set to nCS<3> in order to read the switch
;       setting on GPIO_4_2.
;
        ldr     r1,     =(xlli_MFPR_PHYSICAL_BASE + 0x100)      ; Pointer to MFP Register base + 0x100

        ldr     r2,     [r1, #0x34]     ; Get MFPR data for GPIO_4
        orr     r2,     r2,     #1      ; Set the alternate function to 1 to select nCS<3>
        str     r2,     [r1, #0x34]     ; Write the data back

        mov     r0,     #0x10000        ; Set up a short delay to allow...
xlli_cd subs    r0,     r0,     #1      ; ...nCS<3> to be set up so the... 
        bne     xlli_cd                 ; ...level on GPIO_4 can be read

        ldr     r1,     =xlli_GPIOREGS_PHYSICAL_BASE    ; GPIO regs base address
        ldr     r2,     [r1, #xlli_GPLR0_offset]        ; Get GPIO level values
        mov     r2,     r2,     LSR #4                  ; Move bit #4 to bit #0 position
        and     r0,     r2,     #1      ; Save GPIO_4_2 bit in r0
        mov     r2,     r2,     LSR #2  ; Move bit #7 to bit #1 position
        and     r2,     r2,     #2      ; Isolate this bit (GPIO_7_2)
        orr     r0,     r0,     r2      ; OR this bit into r0
;
;       Set MEMCLKCFG register to processor power on value (clocks divided by 4)
;
        ldr     r1,     =xlli_STAMREGS_PHYSICAL_BASE    ; Static memory config base
        ldr     r2,     =0x00030003                     ; Hard coded reset value
        str     r2,     [r1, #xlli_MEMCLKCFG_offset]    ; Set register to POR value
;
;       r0 now contains the return value based on the platform switch settings.
;
        cmp     r0,     #3              ; Set core to 104 MHz?
        ldreq   r4,     =0x1003108      ; Yes set up ACCR values
        moveq   r5,     #0              ; Turbo off

        cmp     r0,     #2              ; Set core to 208 MHz?
        ldreq   r4,     =0x1087110      ; Yes set up ACCR values
        moveq   r5,     #0              ; Turbo off

        cmp     r0,     #1              ; Set core to 416 MHz?
        ldreq   r4,     =0x28CB210      ; Yes set up ACCR values
        moveq   r5,     #1              ; Turbo on

        cmp     r0,     #0              ; Set core to 624 MHz?
        ldreq   r4,     =0x28CB40C      ; Yes set up ACCR values
        moveq   r5,     #1              ; Turbo on
;
;       Update ACCR register (One bus frequency at a time) SMCFS first
;
        ldr     r1, =xlli_CLKREGS_PHYSICAL_BASE ; Clock register base address
        ldr     r3,     [r1, #xlli_ACCR_offset] ; Fetch the existing ACCR value
        and     r2,     r4,     #0x3800000      ; Get new Static Memory Speed
        bic     r3,     r3,     #0x3800000      ; Clear existing bits in ACCR
        orr     r3,     r3,     r2              ; Update the SMCFS bits
        str     r3,     [r1, #xlli_ACCR_offset] ; Store the updated ACCR value
xlli_FA ldr     r3,     [r1, #xlli_ACSR_offset] ; Fetch ACSR register
        and     r3,     r3,     #0x3800000      ; Extract the SMCFS bits
        cmp     r3,     r2                      ; Do they match?
        bne     xlli_FA                         ; No - loop until they do
;
;       Update SRAM bus frequency
;
        ldr     r3,     [r1, #xlli_ACCR_offset] ; Fetch the existing ACCR value
        and     r2,     r4,     #0xC0000        ; Get new SRAM Memory Speed
        bic     r3,     r3,     #0xC0000        ; Clear existing bits in ACCR
        orr     r3,     r3,     r2              ; Update the SFLFS bits
        str     r3,     [r1, #xlli_ACCR_offset] ; Store the updated ACCR value
xlli_FB ldr     r3,     [r1, #xlli_ACSR_offset] ; Fetch ACSR register
        and     r3,     r3,     #0xC0000        ; Extract the SFLFS bits
        cmp     r3,     r2                      ; Do they match?
        bne     xlli_FB                         ; No - loop until they do
;
;       Update High Speed I/O bus frequency
;
        ldr     r3,     [r1, #xlli_ACCR_offset] ; Fetch the existing ACCR value
        and     r2,     r4,     #0xC000         ; Get new HSIO Memory Speed
        bic     r3,     r3,     #0xC000         ; Clear existing bits in ACCR
        orr     r3,     r3,     r2              ; Update the HSS bits
        str     r3,     [r1, #xlli_ACCR_offset] ; Store the updated ACCR value
xlli_FC ldr     r3,     [r1, #xlli_ACSR_offset] ; Fetch ACSR register
        and     r3,     r3,     #0xC000         ; Extract the HSS bits
        cmp     r3,     r2                      ; Do they match?
        bne     xlli_FC                         ; No - loop until they do
;
;       Update DDR memory bus frequency
;
        ldr     r3,     [r1, #xlli_ACCR_offset] ; Fetch the existing ACCR value
        and     r2,     r4,     #0x3000         ; Get new DMCFS Memory Speed
        bic     r3,     r3,     #0x3000         ; Clear existing bits in ACCR
        orr     r3,     r3,     r2              ; Update the DMCFS bits
        str     r3,     [r1, #xlli_ACCR_offset] ; Store the updated ACCR value
xlli_FD ldr     r3,     [r1, #xlli_ACSR_offset] ; Fetch ACSR register
        and     r3,     r3,     #0x3000         ; Extract the DMCFS bits
        cmp     r3,     r2                      ; Do they match?
        bne     xlli_FD                         ; No - loop until they do
;
;       Update the processor core frequency
;
        ldr     r3,     [r1, #xlli_ACCR_offset] ; Fetch the existing ACCR value
        ldr     r2,     =0x71F                  ; Set up a mask word
        bic     r3,     r3,     r2              ; Clear existing bits in ACCR
        and     r2,     r4,     r2              ; Extract core speed settings
        orr     r3,     r3,     r2              ; Update the XN and XL bits
        str     r3,     [r1, #xlli_ACCR_offset] ; Store the updated ACCR value
;
;       PERFORM THE FREQUENCY CHANGE SEQUENCE
;
        mrc     p14, 0, r2, c6, c0, 0       ; Get present status (preserve Turbo and Fast Bus bits)
        orr     r2,  r2,  #2                ; Set the F bit
        mcr     p14, 0, r2, c6, c0, 0       ; Initiate the frequency change sequence
;
;       Update the turbo bit
;
        mrc     p14,    0, r2, c6, c0, 0        ; Get data in CP14, Register 6
        cmp     r5,     #0                      ; Set or clear Turbo bit?
        orrne   r2,     r2,     #1              ; Set Turbo bit
        biceq   r2,     r2,     #1              ; Clear Turbo bit        
        mcr     p14,    0, r2, c6, c0, 0        ; Write data to CP14, Register 6
;
                IF :DEF: xlli_stack_pointer     ; If stack pointer has been defined,
        ldmfd   sp!,    {r1-r5, pc}             ; return to caller via the stack pointer
                ELSE
        mov     pc,     lr                      ; Non stack return
                ENDIF

        ENDFUNC
        END
